package com.example.financeapi.utils;

import com.example.financeapi.config.constant.APIConstant;
import com.example.financeapi.enums.ResultEnum;
import com.example.financeapi.entity.vo.CheckResult;
import com.example.financeapi.entity.vo.ResultException;
import io.jsonwebtoken.*;
import org.bouncycastle.util.encoders.Base64;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;

/**
 * JWT加密和解密的工具类
 * @author Alvin
 */
public class JWTUtils {

    public static final int JWT_ERROR_CODE_NULL = 4000; // Token不存在
    public static final int JWT_ERROR_CODE_EXPIRE = 4001; // Token过期
    public static final int JWT_ERROR_CODE_FAIL = 4002; // 验证不通过

    /**
     * 签发JWT
     * @param ttlMillis 过期时间
     * @return
     * @throws ResultException
     */
    public static String createJWT(String id,long ttlMillis) throws ResultException {
        try {
            //使用HS256加密算法
            SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
            long nowMillis = System.currentTimeMillis();
            Date now = new Date(nowMillis);
            //生成签名密钥
            SecretKey secretKey = generalKey();
            //添加构成JWT的参数
            JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT")
                    .setId(id)
                    /**主题*/
                    .setSubject("JWT-Token")
                    /**签发者*/
                    .setIssuer("Alvin")
                    /** 签发时间*/
                    .setIssuedAt(now)
                    /** 签名算法以及密匙*/
                    .signWith(signatureAlgorithm, secretKey);
            //添加Token过期时间
            if (ttlMillis >= 0) {
                long expMillis = nowMillis + ttlMillis;
                /**JWT的过期时间*/
                Date expDate = new Date(expMillis);
                builder.setExpiration(expDate)
                        /**JWT生效的开始时间，意味着在这个时间之前验证JWT是会失败的*/
                        .setNotBefore(now);
            }
            return builder.compact();
        }catch (Exception e){
            throw new ResultException(ResultEnum.PROGRAM_EXCEPTION,e);
        }
    }

    /**
     * 验证JWT
     * @param jwtStr
     * @return  CheckResult
     */
    public static CheckResult validateJWT(String jwtStr) {
        CheckResult checkResult = new CheckResult();
        Claims claims;
        try {
            claims = parseJWT(jwtStr);
            checkResult.setSuccess(true);
            checkResult.setClaims(claims);
        } catch (ExpiredJwtException e) {
            checkResult.setErrCode(JWT_ERROR_CODE_EXPIRE);
            checkResult.setSuccess(false);
        } catch (SignatureException e) {
            checkResult.setErrCode(JWT_ERROR_CODE_FAIL);
            checkResult.setSuccess(false);
        } catch (Exception e) {
            checkResult.setErrCode(JWT_ERROR_CODE_FAIL);
            checkResult.setSuccess(false);
        }
        return checkResult;
    }

    /**
     * 生成密钥
     * @return
     */
    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.decode(APIConstant.JWT_SERCERT.getBytes());
        return new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
    }

    /**
     * 解析JWT字符串
     * @param jwt
     * @return
     * @throws Exception  Claims
     */
    public static Claims parseJWT(String jwt) {
        SecretKey secretKey = generalKey();
        return Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(jwt)
                .getBody();
    }

    /**
     * 从token中获取用户ID解密
     * @param token
     * @return
     */
    public static String getUserId(String token){
        return parseJWT(token).getId();
    }

}